package com.ics.cmsadmin.modules.agent.service.impl;

import com.ics.cmsadmin.frame.constant.Constants;
import com.ics.cmsadmin.frame.core.bean.PageBean;
import com.ics.cmsadmin.frame.core.bean.PageResult;
import com.ics.cmsadmin.frame.core.enums.ApiResultEnum;
import com.ics.cmsadmin.frame.core.exception.CmsException;
import com.ics.cmsadmin.frame.profit.ProfitInfo;
import com.ics.cmsadmin.frame.profit.ProfitTypeEnum;
import com.ics.cmsadmin.modules.agent.bean.AgentInfoBean;
import com.ics.cmsadmin.modules.agent.bean.AgentShareRuleBean;
import com.ics.cmsadmin.modules.agent.bean.ShareDetailBean;
import com.ics.cmsadmin.modules.agent.enums.AccountChangesEnum;
import com.ics.cmsadmin.modules.agent.service.ShareDetailService;
import com.ics.cmsadmin.modules.basic.bean.OrderBean;
import com.ics.cmsadmin.modules.basic.dao.OrderDao;
import com.ics.cmsadmin.modules.system.emums.RegisterKeyValueEnum;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang.time.DateFormatUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Date;
import java.util.Optional;

import static com.ics.cmsadmin.modules.agent.steward.AgentRepositories.shareDetailDao;
import static com.ics.cmsadmin.modules.agent.steward.AgentServices.*;
import static com.ics.cmsadmin.modules.auth.steward.AuthServices.accessService;
import static com.ics.cmsadmin.modules.system.steward.SystemServices.registerService;
/**
 * a_share_detail
 * Created bylvsw on 2018-37-29 16:09:14.
 */
@Log4j2
@Service
public class ShareDetailServiceImpl implements ShareDetailService {

    @Resource
    private OrderDao orderDao;

    @Override
    public PageResult<ShareDetailBean> listByLoginUserId(ShareDetailBean bean, String loginUserId, PageBean page) {
        return listByLoginUserId(bean, loginUserId, page, shareDetailDao);
    }

    @Override
    public boolean generateShareByOrderId(String orderId) {
        if (StringUtils.isBlank(orderId)){
            throw new CmsException(ApiResultEnum.INSERT_TABLE_ITEM_FAIL, "订单id不能为空");
        }
        OrderBean orderBean = orderDao.findOne(OrderBean.builder().id(orderId).status(2).accStatus("0").build());
        if (orderBean == null){
            throw new CmsException(ApiResultEnum.INSERT_TABLE_ITEM_FAIL, "订单不存在或者未支付");
        }
        if (StringUtils.isBlank(orderBean.getAgentNo()) || StringUtils.equalsIgnoreCase("0", orderBean.getAgentNo())) {
            log.warn("该代理商为顶级分销商,不需要分润");
            orderDao.updateNotIntoAccount(orderId);
            return true;
        }
        AgentInfoBean agentInfoBean = agentInfoService.queryById(orderBean.getAgentNo());
        if (agentInfoBean == null){
            throw new CmsException(ApiResultEnum.INSERT_TABLE_ITEM_FAIL, "分销商不存在");
        }
        if (StringUtils.equalsIgnoreCase(agentInfoBean.getStatus(), Constants.DISABLE_STATUS)){
            log.warn("分销商{}是禁用状态,不予分润", agentInfoBean.getAgentNo());
            orderDao.updateNotIntoAccount(orderId);
            return true;
        }
        AgentShareRuleBean agentShareRuleBean = agentShareRuleService.queryByAgentNo(agentInfoBean.getAgentNo());
        if (agentShareRuleBean == null){
            throw new CmsException(ApiResultEnum.INSERT_TABLE_ITEM_FAIL, "分销商分润规则不存在");
        }

        String orderPayTime = DateFormatUtils.format(Optional.ofNullable(orderBean.getPayTime()).orElse(new Date()),
            "yyyy-MM-dd HH:mm:ss");
        long studentNum = orderDao.countDistinctBuyOrderStudentNum(agentInfoBean.getAgentNo(), orderPayTime);
        ProfitTypeEnum profitTypeEnum = ProfitTypeEnum.valueOfProfitType(agentShareRuleBean.getType());
        if (profitTypeEnum == null){
            throw new CmsException(ApiResultEnum.INSERT_TABLE_ITEM_FAIL, "不支持该分润规则类型");
        }
        synchronized (agentInfoBean.getAgentNo().intern()){
            // 1. 计算直推分润
            OrderBean one = orderDao.findOne(OrderBean.builder().id(orderId).status(2).accStatus("0").build());
            if (one == null){
                throw new CmsException(ApiResultEnum.INSERT_TABLE_ITEM_FAIL, "订单未支付或已入账,不必重复计算");
            }
            profitTypeEnum.getFactory().verifyExpression(agentShareRuleBean.getExpression());
            ProfitInfo profitInfo = profitTypeEnum.getProfitRole(agentShareRuleBean.getExpression())
                .getProfitInfo(orderBean.getOrderAmount(), studentNum);
            shareDetailDao.insert(ShareDetailBean.builder()
                .agentNo(agentInfoBean.getAgentNo())
                .shareType("0")
                .shareMoney(profitInfo.getShareMonery())
                .orderMoney(profitInfo.getOrderMoney())
                .shareRate(profitInfo.getShareRate())
                .orderId(orderId)
                .studentId(orderBean.getUserId())
                .sourceAgentNo(agentInfoBean.getAgentNo())
                .studentNum(studentNum + "")
                .build());
            agentAccountService.accountChanges(agentInfoBean.getAgentNo(),
                profitInfo.getShareMonery(), AccountChangesEnum.PROFIT_INCOME);

            // 2 计算上级分润
            AgentInfoBean oneAgentInfo = agentInfoService.queryById(agentInfoBean.getParentId());
            if (oneAgentInfo != null && StringUtils.equalsIgnoreCase(oneAgentInfo.getStatus(), Constants.ENABLE_STATUS)){
                BigDecimal oneAgentRate = registerService.queryRegisterValue(RegisterKeyValueEnum.ONE_AGENT_SHARE_RATE, BigDecimal::new);
                BigDecimal oneShareMoney = orderBean.getOrderAmount().multiply(oneAgentRate).multiply(new BigDecimal("0.01"));
                shareDetailDao.insert(ShareDetailBean.builder()
                    .agentNo(oneAgentInfo.getAgentNo())
                    .shareType("1")
                    .shareMoney(oneShareMoney)
                    .orderMoney(profitInfo.getOrderMoney())
                    .shareRate(oneAgentRate)
                    .orderId(orderId)
                    .studentId(orderBean.getUserId())
                    .sourceAgentNo(agentInfoBean.getAgentNo())
                    .build());
                agentAccountService.accountChanges(oneAgentInfo.getAgentNo(),
                    oneShareMoney, AccountChangesEnum.PROFIT_INCOME);
            }
            orderDao.updateIntoAccount(orderId);
        }
        return true;
    }
}
